package cn.daniellee.plugin.pr.storage;

import cn.daniellee.plugin.pr.PlotRedstone;
import cn.daniellee.plugin.pr.model.PlayerData;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.lang.StringUtils;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class SqliteStorage extends Storage {

	private Connection connection;

	@Override
	public boolean initialize() {
		// 初始化Mysql驱动
		try {
			Class.forName("org.sqlite.JDBC");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			PlotRedstone.getInstance().getLogger().info(" ");
			PlotRedstone.getInstance().getLogger().info("[PartnerMission]An error occurred while getting the sqlite database driver.".replace("&", "§"));
			PlotRedstone.getInstance().getLogger().info(" ");
			return false;
		}
		// 初始化连接
		String url = "jdbc:sqlite:" + PlotRedstone.getInstance().getDataFolder().getAbsolutePath() + "/storage.db";
		try {
			connection = DriverManager.getConnection(url);
		} catch (SQLException e) {
			e.printStackTrace();
			PlotRedstone.getInstance().getLogger().info(" ");
			PlotRedstone.getInstance().getLogger().info("[PartnerMission]Sqlite connection information is incorrect.".replace("&", "§"));
			PlotRedstone.getInstance().getLogger().info(" ");
			return false;
		}
		// 初始化数据表
		PreparedStatement statement = null;
		String sql = "CREATE TABLE IF NOT EXISTS player (" +
				"`name` VARCHAR(48) PRIMARY KEY NOT NULL," +
				"`enabled` BOOLEAN DEFAULT FALSE," +
				"`contact` VARCHAR(64)," +
				"`introduction` TEXT," +
				"`by_times` BOOLEAN DEFAULT FALSE," +
				"`show_offline` BOOLEAN DEFAULT FALSE," +
				"`online_minutes` INT," +
				"`finish_times` INT," +
				"`last_finish` INT" +
				")";
		try {
			statement = connection.prepareStatement(sql);
			statement.execute();
		} catch (SQLException e) {
			e.printStackTrace();
			PlotRedstone.getInstance().getLogger().info(" ");
			PlotRedstone.getInstance().getLogger().info("[PartnerMission]An error occurred while initializing the Mysql mission table.".replace("&", "§"));
			PlotRedstone.getInstance().getLogger().info(" ");
			return false;
		} finally {
			if (statement != null) {
				try {
					statement.close();
				} catch (SQLException ignored) { }
			}
		}
		return true;
	}

	@Override
	public List<PlayerData> getAllEnabledPlayer(String exclude) {
		List<PlayerData> allPlayerData = new ArrayList<>();
		PreparedStatement statement = null;
		try {
			String sql = "SELECT * FROM `player` WHERE `enabled` = 1 AND `name` != ?;";
			statement = connection.prepareStatement(sql);
			statement.setString(1, exclude);
			ResultSet resultSet = statement.executeQuery();
			while (resultSet.next()) {
				PlayerData playerData = new PlayerData(resultSet.getString("name"), resultSet.getBoolean("enabled"), resultSet.getString("contact"), new Gson().fromJson(resultSet.getString("introduction"), new TypeToken<List<String>>(){}.getType()), resultSet.getBoolean("by_times"), resultSet.getBoolean("show_offline"), resultSet.getInt("online_minutes"), resultSet.getInt("finish_times"), resultSet.getLong("last_finish"));
				allPlayerData.add(playerData);
			}
		} catch (SQLException e) {
			e.printStackTrace();
			PlotRedstone.getInstance().getLogger().info(" ");
			PlotRedstone.getInstance().getLogger().info("[PartnerMission]An error occurred while reading building data from Mysql.".replace("&", "§"));
			PlotRedstone.getInstance().getLogger().info(" ");
		} finally {
			if (statement != null) {
				try {
					statement.close();
				} catch (SQLException ignored) { }
			}
		}
		return allPlayerData;
	}

	@Override
	public PlayerData getPlayerByName(String name) {
		PlayerData playerData = null;
		PreparedStatement statement = null;
		try {
			String sql = "SELECT * FROM `player` WHERE `name` = ? LIMIT 1;";
			statement = connection.prepareStatement(sql);
			statement.setString(1, name);
			ResultSet resultSet = statement.executeQuery();
			if (resultSet.next()) {
				playerData = new PlayerData(resultSet.getString("name"), resultSet.getBoolean("enabled"), resultSet.getString("contact"), new Gson().fromJson(resultSet.getString("introduction"), new TypeToken<List<String>>(){}.getType()), resultSet.getBoolean("by_times"), resultSet.getBoolean("show_offline"), resultSet.getInt("online_minutes"), resultSet.getInt("finish_times"), resultSet.getLong("last_finish"));
			}
		} catch (SQLException e) {
			e.printStackTrace();
			PlotRedstone.getInstance().getLogger().info(" ");
			PlotRedstone.getInstance().getLogger().info("[PartnerMission]An error occurred while reading building data from Mysql.".replace("&", "§"));
			PlotRedstone.getInstance().getLogger().info(" ");
		} finally {
			if (statement != null) {
				try {
					statement.close();
				} catch (SQLException ignored) { }
			}
		}
//		if (playerData == null) playerData = RedstoneCore.initializePlayer(name);
		return playerData;
	}

	@Override
	public void addPlayer(PlayerData playerData) {
		PreparedStatement statement = null;
		try {
			String sql = "INSERT INTO `player` (`name`,`enabled`,`contact`,`introduction`,`by_times`,`show_offline`,`online_minutes`,`finish_times`,`last_finish`)VALUES(?,?,?,?,?,?,?,?,?)";
			statement = connection.prepareStatement(sql);
			statement.setString(1, playerData.getName());
			statement.setBoolean(2, playerData.isEnabled());
			statement.setString(3, playerData.getContact());
			statement.setString(4, new Gson().toJson(playerData.getIntroduction()));
			statement.setBoolean(5, playerData.isByTimes());
			statement.setBoolean(6, playerData.isShowOffline());
			statement.setInt(7, playerData.getOnlineMinutes());
			statement.setInt(8, playerData.getFinishTimes());
			statement.setLong(9, playerData.getLastFinish());
			statement.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
			PlotRedstone.getInstance().getLogger().info(" ");
			PlotRedstone.getInstance().getLogger().info("[PartnerMission]An error occurred while writing building data to Mysql.".replace("&", "§"));
			PlotRedstone.getInstance().getLogger().info(" ");
		} finally {
			if (statement != null) {
				try {
					statement.close();
				} catch (SQLException ignored) { }
			}
		}
	}

	@Override
	public void updatePlayer(String name, Map<String, Object> fields) {
		PreparedStatement statement = null;
		try {
			String sql = "UPDATE `player` SET " + StringUtils.join(fields.keySet().stream().map(o -> o + "=?").toArray(),",") + " WHERE `name` = ?";
			statement = connection.prepareStatement(sql);
			String[] keys = fields.keySet().toArray(new String[]{});
			for (int i = 0; i < keys.length; i++) statement.setObject(i + 1, fields.get(keys[i]));
			statement.setString(keys.length + 1, name);
			statement.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
			PlotRedstone.getInstance().getLogger().info(" ");
			PlotRedstone.getInstance().getLogger().info("[PartnerMission]An error occurred while writing building data to Mysql.".replace("&", "§"));
			PlotRedstone.getInstance().getLogger().info(" ");
		} finally {
			if (statement != null) {
				try {
					statement.close();
				} catch (SQLException ignored) { }
			}
		}
	}

	public void close() {
		try {
			connection.close();
		} catch (SQLException ignored) { }
	}
}
